package org.jclip.browser;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.xml.parsers.*;

import net.infonode.docking.DockingWindow;
import net.infonode.docking.RootWindow;
import net.infonode.docking.SplitWindow;
import net.infonode.docking.TabWindow;
import net.infonode.docking.View;
import net.infonode.docking.theme.DockingWindowsTheme;
import net.infonode.docking.theme.ShapedGradientDockingTheme;
import net.infonode.docking.util.DockingUtil;
import net.infonode.docking.util.ViewMap;
import net.infonode.util.Direction;

import org.jclip.runtime.Browser;
import org.jclip.runtime.JavaClientPage;
import org.jclip.runtime.ValidationError;

import java.util.HashMap;
import java.util.Stack;
import org.w3c.dom.*;

public class App extends JFrame implements Browser {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	protected JTextField address;
	protected JPanel curTab;
	private HashMap<String,Object> hm = new HashMap<String, Object>();
	private Stack<String> st = new Stack<String>();
	private Stack<String> st2 = new Stack<String>();
	private	JPanel problemsPanel = new JPanel();
	private RootWindow rootWindow ;
	private View[] views = new View[10];
	private ViewMap viewMap = new ViewMap();
	private TabWindow tabbed ;
	private JTable table = new JTable();
	private DefaultTableModel model = new DefaultTableModel(
        	new Object[][] { },
        	new String[] {
        		"Message", "Description", "Source"
        	}
        ){
		/**
			 * 
			 */
		private static final long serialVersionUID = 1L;

		public boolean isCellEditable(int row, int column){
			return false;
		}
	};




	
	public App() {
		
	}	
	
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
       new App().run();
	}
	
   	public void run() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException  {
   		
   		init();
		address.addKeyListener(new KeyListener() {
			
			@Override
			public void keyTyped(KeyEvent arg0) {}
			
			@Override
			public void keyReleased(KeyEvent arg0) {}
			
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					go(address.getText(), hm);
					
					
				}
			}
		});
		
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		go("http://localhost//org.jclip.examples.helloworld//bin//#org.jclip.examples.helloworld.DoodlePanel2",hm);		
		setVisible(true);
	}
	
	public void go(String location, HashMap<String,Object> hash)  {
		try {
			model.getDataVector().removeAllElements();
			table.repaint();
			
			JMenuBar mnBar = getJMenuBar();
			if(mnBar.getMenuCount()>2){
				for(int i=2; i<mnBar.getMenuCount(); i++)
				{
					mnBar.remove(i);
				}
			}
			
			String cls = readXML(location);
			String url;
			String className;

			if(cls==null){
				hm.putAll(hash);
				st.push(location);
			
				address.setText(location);

				String[] parts = location.split("#");
				url = parts[0];
				className = parts[1];
			
			}  else {
				hm.putAll(hash);
				st.push(cls);
				
			    address.setText(cls);

				String[] parts = cls.split("#");
				url = parts[0];
				className = parts[1];
			}
			
				
				URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL(url)}) ;
				Class<?> clazz = classLoader.loadClass(className);

				Constructor<?> c = clazz.getConstructor(new Class[]{HashMap.class});
				Object newInstance = (Object) c.newInstance(new Object[]{hm});

				
				if (newInstance instanceof JavaClientPage){
					JavaClientPage page = (JavaClientPage) newInstance;
					page.setBrowser(this);
					curTab.removeAll();
					curTab.add(page, BorderLayout.CENTER);
					JMenu menu = page.getMenus();
					mnBar.add(menu);
					setTitle(page.getTitle());
					curTab.updateUI();
			}
		}
			
		
		catch (Exception ex) {
           		ex.printStackTrace();
						
		}	
	}

	
	
		
	private void init()
	{	
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setTitle("JClip Browser");
		setBounds(new Rectangle(50, 50, 800, 700));

		
		JPanel upperPanel = new JPanel();
		getContentPane().add(upperPanel, BorderLayout.NORTH);
		upperPanel.setLayout(new BorderLayout(0, 0));
		
		JPanel display = new JPanel();
		display.setLayout(new BorderLayout(0, 0));
		curTab = display;
		
		JScrollPane lowerPane = new JScrollPane(curTab);
		getContentPane().add(lowerPane, BorderLayout.CENTER);
		
		problemsPanel.setBackground(new Color(255,255,255));
		problemsPanel.setLayout(new BorderLayout(0,0));
		JScrollPane problemsPane = new JScrollPane();
		problemsPane.setViewportView(makeTable());
		problemsPanel.add(problemsPane, BorderLayout.CENTER);
		
		address = new JTextField();
		upperPanel.add(address, BorderLayout.CENTER);
		address.setColumns(10);
		
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);		
		JMenu mnFile = new JMenu("File");
		menuBar.add(mnFile);		
		JMenuItem mntmNew = new JMenuItem("New tab");
		mnFile.add(mntmNew);
		mntmNew.addActionListener(new ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				JPanel jpanel = new JPanel();
				curTab = jpanel;
				curTab.setBackground(Color.WHITE);
				curTab.setLayout(new BorderLayout(0,0));
				int index = tabbed.getChildWindowCount();
				viewMap.addView(index, views[index]);
				tabbed.addTab(new View(address.getText().substring(0,12), null, curTab), index);
				rootWindow.updateUI();
			}
		});
		JMenuItem mntmClose = new JMenuItem("Close");
		mnFile.add(mntmClose);
		JMenu mnHelp = new JMenu("Help");
		menuBar.add(mnHelp);
		JMenuItem mntmAbout = new JMenuItem("About..");
		mnHelp.add(mntmAbout);
		
		JPanel innerPanel = new JPanel();
		upperPanel.add(innerPanel, BorderLayout.WEST);
		innerPanel.setLayout(new BorderLayout(0, 0));
		
		JButton btnBack = new JButton("");
		btnBack.setPreferredSize(new Dimension(25, 25));
		btnBack.setIcon(new ImageIcon(App2.class.getResource("/org/jclip/browser/arrow-back-1.png")));
		innerPanel.add(btnBack, BorderLayout.WEST);
		btnBack.addActionListener(new ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt){
				st2.push(st.pop());
				go(st.pop(),hm);
			
			}
		});
		
		JButton btnFwd = new JButton("");
		btnFwd.setPreferredSize(new Dimension(25, 25));
		btnFwd.setIcon(new ImageIcon(App2.class.getResource("/org/jclip/browser/arrow-forward-1.png")));
		innerPanel.add(btnFwd, BorderLayout.EAST);
		btnFwd.addActionListener(new ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				st.push(st2.pop());
				go(st.pop(), hm);
			}
		});
		
		JButton btnNewButton = new JButton("");
		btnNewButton.setPreferredSize(new Dimension(25, 25));
		btnNewButton.setIcon(new ImageIcon(App2.class.getResource("/org/jclip/browser/next.png")));
		upperPanel.add(btnNewButton, BorderLayout.EAST);
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				go(address.getText(), hm);
			}
		});
		upperPanel.add(btnNewButton, BorderLayout.EAST);
		        
		views[0] = new View("New Tab" , null, curTab);
		viewMap.addView(0, views[0]);       
		views[1] = new View("Errors", null, problemsPane);
		
		rootWindow = DockingUtil.createRootWindow(viewMap, true);
		rootWindow.getWindowBar(Direction.DOWN).setEnabled(true);
		tabbed = new TabWindow(new DockingWindow[]{views[0]});
		SplitWindow sw = new SplitWindow(false, 0.8f, tabbed, views[1]);
		rootWindow.getRootWindowProperties().getSplitWindowProperties().setDividerLocationDragEnabled(false);
		rootWindow.setWindow(sw);
		DockingWindowsTheme theme = new ShapedGradientDockingTheme();
		
		// Apply theme
		rootWindow.getRootWindowProperties().addSuperObject(
		theme.getRootWindowProperties());
		add(rootWindow).setVisible(true);
		
	}
	
	@SuppressWarnings("null")
	public void reportErrors(java.util.List<ValidationError> warnings)
	{
		if(warnings!=null){
			model.getDataVector().removeAllElements();
			table.repaint();
			
		for(int i=0; i<warnings.size(); i++){
		    ValidationError e = warnings.get(i);
		    if(e.getWarning()==true){
			model.addRow(new Object[]{e.getMessage(), e.getDescription(), e.getComponent()});
			 table.addMouseListener(new MouseAdapter() {
		            public void mouseClicked(MouseEvent e) {
		            if (e.getClickCount() == 1) { 
		            JTable target = (JTable)e.getSource();
		            int row = target.getSelectedRow(); // i just care about rows but i imagine you can get collumns
		            int column = target.getSelectedColumn();
		            if(target.getValueAt(row,column) instanceof JComponent){
		            JComponent comp  = (JComponent) target.getValueAt(row,column);
		            comp.setForeground(Color.RED);
		            comp.scrollRectToVisible(new Rectangle(comp.getX()-20, comp.getY()-20, 1, 1));
		            }
		            }}});

			}}
		}
		
	}
	public String readXML(String filePath){
		try {
			int index = filePath.lastIndexOf("//");
			String split = filePath.substring(0,index);
			String xmlFilePath = split+"//mappings.xml";
			
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			Document doc = dBuilder.parse(new URL(xmlFilePath).openStream());
			doc.getDocumentElement().normalize();
			
			NodeList nList = doc.getElementsByTagName("javaclientpage");
			
 
			for (int temp = 0; temp < nList.getLength(); temp++) {
 
				Node nNode = nList.item(temp);
				if (nNode.getNodeType() == Node.ELEMENT_NODE) {
 
					Element eElement = (Element) nNode;
					String name = getTagValue("name", eElement);
					String cls = getTagValue( "class" , eElement );
					
					String userName = filePath.substring(index+2);

					if(userName.equals(name)){
						System.out.println(split+"//#"+cls);
						return split+"//#"+cls;
					}
				} 
			}
			} catch (Exception e) {
			e.printStackTrace();
			}
		return null;
	}
	
	private static String getTagValue(String sTag, Element eElement) {
			NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
		 
		        Node nValue = (Node) nlList.item(0);
		 
			return nValue.getNodeValue();
		  }


    private JTable makeTable()
     {

        table.setRowHeight(22);
        table.setRowSelectionAllowed(false);
        table.setRowMargin(1);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
        table.setIntercellSpacing(new Dimension(5, 5));
        table.setFillsViewportHeight(true);
        table.setFont(new Font("Tahoma", Font.PLAIN, 14));
        table.setBounds(new Rectangle(0,11,0,0));
        table.setModel(model);
        
        return table;
     }
 }